package com.jt.service;

import com.jt.vo.ImageVO;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;

/**
 * 文件上传
 */
@Service
@PropertySource("classpath:/properties/image.properties")
public class FileServiceImpl implements FileService {

    //定义图片的类型集合
    private static Set<String> imageTypeSet = new HashSet<>();

    //为属性动态赋值
    @Value("${image.localDirPath}")
    private String localDirPath;     //= "E:/JT-SOFT/images";   定义了本地磁盘路径
    @Value("${image.urPath}")
    private String urlPath;          //= "http://image.jt.com"; 定义了虚拟路径的域名

    static {
        imageTypeSet.add(".jpg");
        imageTypeSet.add(".jpeg");
        imageTypeSet.add(".png");
        imageTypeSet.add(".gif");
    }

    /**
     * 1.校验文件有效性                .jpg/.png/.gif......
     * 2.校验文件是否为恶意程序        (校验后缀是否被恶意修改成.jpg)
     * 3.提高用户检索图片的效率        所以要分目录存储
     * 4.防止重名图片上传              所以要自定义文件的名称
     * 5.实现图片的物理上传            上传到本地磁盘中
     * 6.准备一个访问图片的虚拟路径
     */
    @Override
    public ImageVO upload(MultipartFile uploadFile) {
        //1.校验图片类型
        //1.1获取图片名称
        String fileName = uploadFile.getOriginalFilename();
        fileName = fileName.toLowerCase();  //将文件的所有字母都转换为小写
        //1.2获取图片类型
        int index = fileName.lastIndexOf(".");  //获取 . 所在的位置
        String fileType = fileName.substring(index);    //根据它的位置开始截取后缀
        if(!imageTypeSet.contains(fileType)){    //如果类型不匹配则返回失败信息
            return  ImageVO.fail();     //图片上传失败
        }

        //2.1将上传的文件类型利用图片的API进行转化  如果转化不成功则一定不是图片
        try {
            BufferedImage bufferedImage = ImageIO.read(uploadFile.getInputStream());
            //2.2校验是否有图片的特有属性   宽度/高度
            int width = bufferedImage.getWidth();   //获取宽度
            int height = bufferedImage.getHeight(); //获取高度
            //2.3进行校验，如果有一个为0都直接返回失败
            if(width==0||height==0){
                return ImageVO.fail();
            }
        } catch (IOException e) {
            e.printStackTrace();
            return ImageVO.fail();  //出现异常也同样返回失败
        }

        //3.实现分目录存储
        // 方案1：利用hash之后每隔2-3位截取之后拼接
        // 方案2：以时间为单位进行分隔   /yyyy/MM/dd/
        //3.1 利用工具API将时间转化为指定的格式
        String datePath = new SimpleDateFormat("/yyyy/MM/dd/").format(new Date());
        //3.2 动态生成文件最终目录  最终目录 = 根目录+时间目录
        String localDir = localDirPath + datePath;
        //3.3 将最终目录传给File
        File dirFile = new File(localDir);
        //判断是否有这个目录，没有则创建
        if(!dirFile.exists()){
            dirFile.mkdirs();
        }

        //4.防止文件重名，需要自定义文件名称
        //4.1 生成uuid主键
        /**
         * replace("-", "") 意思是为生成的uuid将其中的 "-" 换成字符串空 ，也就是去掉 "-"
         * 如果没有这句代码 ，那么生成的字符串为  b8b6f3ef-c838-475f-8245-4f67dff5b1fb
         * 加了它之后就变成     b8b6f3efc838475f82454f67dff5b1fb
         */
        String uuid = UUID.randomUUID().toString().replace("-", "");
        //4.2 动态生成文件名  uuid+后缀
        String uuidFileName = uuid + fileType;    //(fileType：前面截取下来的后缀)

        //5. 实现文件的上传  准备好文件全路径   存放的目录+文件名称
        String realFilePath = localDir + uuidFileName;  //到了此处  realFilePath 已经为文件最终所存放的目录+文件名了
        //5.1 封装文件的真实对象
        File imageFile = new File(realFilePath);
        //5.2 实现文件上传
        try {
            uploadFile.transferTo(imageFile);
        } catch (IOException e) {
            e.printStackTrace();
            return ImageVO.fail();
        }

        //6.实现路径拼接
        /**
         * urlPath：虚拟路径域名
         * datePath：当前时间转换过来的磁盘目录
         * uuidFileName：最终生成的文件名
         */
        String url = urlPath + datePath + uuidFileName;
        return ImageVO.success(url);
    }
}
